{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "b6399d63",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "from torch.nn import functional as F\n",
    "\n",
    "from torchvision import datasets\n",
    "from torchvision import transforms\n",
    "from torch.utils.data import DataLoader\n",
    "\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "from matplotlib import gridspec\n",
    "\n",
    "import numpy as np\n",
    "\n",
    "import os\n",
    "os.environ[\"KMP_DUPLICATE_LIB_OK\"]=\"TRUE\"\n",
    "\n",
    "from IPython import display"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d9eb0c00",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 判断是否有GPU\n",
    "\n",
    "device = \"cuda:0\" if torch.cuda.is_available() else \"cpu\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3adb1aca",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    加载数据\n",
    "    - 模仿的对象\n",
    "    - 真品\n",
    "\"\"\"\n",
    "\n",
    "# 加载并预处理图像\n",
    "data = datasets.MNIST(root=\"data\", \n",
    "                      train=True, \n",
    "                      transform = transforms.Compose(transforms=[transforms.ToTensor(),\n",
    "                                                                transforms.Normalize(mean=[0.5], std=[0.5])]),\n",
    "                      download=True)\n",
    "\n",
    "# 封装成 DataLoader\n",
    "data_loader = DataLoader(dataset=data, batch_size=100, shuffle=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "213afb54",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([100, 1, 28, 28])\n",
      "torch.Size([100])\n"
     ]
    }
   ],
   "source": [
    "for image, label in data_loader:\n",
    "    print(image.shape)\n",
    "    print(label.shape)\n",
    "    break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f0662964",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    定义生成器\n",
    "\"\"\"\n",
    "\n",
    "class Generator(nn.Module):\n",
    "    \"\"\"\n",
    "        定义一个图像生成\n",
    "        输入：一个向量(随机噪声)\n",
    "        输出：一个向量（代表图像）\n",
    "    \"\"\"\n",
    "    def __init__(self, in_features=100, out_features=28 * 28):\n",
    "        \"\"\"\n",
    "            挂载超参数\n",
    "        \"\"\"\n",
    "        # 先初始化父类，再初始化子类\n",
    "        super(Generator, self).__init__()\n",
    "        \n",
    "        self.in_features = in_features\n",
    "        self.out_features = out_features\n",
    "        \n",
    "        # 第一个隐藏层\n",
    "        self.hidden0 = nn.Linear(in_features=self.in_features, out_features=256)\n",
    "        \n",
    "        # 第二个隐藏层\n",
    "        self.hidden1 = nn.Linear(in_features=256, out_features=512)\n",
    "        \n",
    "        # 第三个隐藏层\n",
    "        self.hidden2 = nn.Linear(in_features=512, out_features=self.out_features)\n",
    "    \n",
    "    def forward(self, x):\n",
    "        \n",
    "        # 第一层 [b, 100] --> [b, 256]\n",
    "        h = self.hidden0(x)\n",
    "        h = F.leaky_relu(input=h, negative_slope=0.2)\n",
    "        \n",
    "        # 第二层 [b, 256] --> [b, 512]\n",
    "        h = self.hidden1(h)\n",
    "        h = F.leaky_relu(input=h, negative_slope=0.2)\n",
    "        \n",
    "        # 第三层 [b, 512] --> [b, 28 * 28]\n",
    "        h = self.hidden2(h)\n",
    "        \n",
    "        # 压缩数据的变化范围\n",
    "        o = torch.tanh(h)\n",
    "        \n",
    "        return o"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "9550e835",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    定义一个鉴别器\n",
    "\"\"\"\n",
    "\n",
    "class Discriminator(nn.Module):\n",
    "    \"\"\"\n",
    "        本质：二分类分类器\n",
    "        输入：一个对象\n",
    "        输出：真品还是赝品\n",
    "    \"\"\"\n",
    "    def __init__(self, in_features=28*28, out_features=1):\n",
    "        super(Discriminator, self).__init__()\n",
    "        \n",
    "        self.in_features=in_features\n",
    "        self.out_features=out_features\n",
    "        \n",
    "        # 第一个隐藏层\n",
    "        self.hidden0= nn.Linear(in_features=self.in_features, out_features=512)\n",
    "        \n",
    "        # 第二个隐藏层\n",
    "        self.hidden1= nn.Linear(in_features=512, out_features=256)\n",
    "        \n",
    "        # 第三个隐藏层\n",
    "        self.hidden2= nn.Linear(in_features=256, out_features=32)\n",
    "        \n",
    "        # 第四个隐藏层\n",
    "        self.hidden3= nn.Linear(in_features=32, out_features=self.out_features)\n",
    "        \n",
    "    \n",
    "    def forward(self, x):\n",
    "        \n",
    "        # 第一层\n",
    "        h = self.hidden0(x)\n",
    "        h = F.leaky_relu(input=h, negative_slope=0.2)\n",
    "        h = F.dropout(input=h, p=0.2)\n",
    "        \n",
    "        # 第二层\n",
    "        h = self.hidden1(h)\n",
    "        h = F.leaky_relu(input=h, negative_slope=0.2)\n",
    "        h = F.dropout(input=h, p=0.2)\n",
    "        \n",
    "        # 第三层\n",
    "        h = self.hidden2(h)\n",
    "        h = F.leaky_relu(input=h, negative_slope=0.2)\n",
    "        h = F.dropout(input=h, p=0.2)\n",
    "        \n",
    "        # 第四层\n",
    "        h = self.hidden3(h)\n",
    "        \n",
    "        # 输出概率\n",
    "        o = torch.sigmoid(h)\n",
    "        \n",
    "        return o"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "f9acef33",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Discriminator(\n",
       "  (hidden0): Linear(in_features=784, out_features=512, bias=True)\n",
       "  (hidden1): Linear(in_features=512, out_features=256, bias=True)\n",
       "  (hidden2): Linear(in_features=256, out_features=32, bias=True)\n",
       "  (hidden3): Linear(in_features=32, out_features=1, bias=True)\n",
       ")"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"\"\"\n",
    "    构建模型\n",
    "\"\"\"\n",
    "# 定义一个生成器\n",
    "generator = Generator(in_features=100, out_features=784)\n",
    "generator.to(device=device)\n",
    "\n",
    "# 定义一个鉴别器\n",
    "discriminator = Discriminator(in_features=784, out_features=1)\n",
    "discriminator.to(device=device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "88cb9255",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    定义优化器\n",
    "\"\"\"\n",
    "\n",
    "# 定义一个生成器的优化器\n",
    "g_optimizer = torch.optim.Adam(params=generator.parameters(), lr=1e-4)\n",
    "\n",
    "# 定义一个鉴别的优化器\n",
    "d_optimizer = torch.optim.Adam(params=discriminator.parameters(), lr=1e-4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "1886dd52",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    定义一个损失函数\n",
    "\"\"\"\n",
    "loss_fn = nn.BCELoss()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "361ea6e4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义训练轮次\n",
    "num_epochs = 1000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "5b7af8d3",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    获取数据的标签\n",
    "\"\"\"\n",
    "\n",
    "def get_real_data_labels(size):\n",
    "    \"\"\"\n",
    "        获取真实数据的标签\n",
    "        所有的真实数据标签都是1\n",
    "    \"\"\"\n",
    "    labels = torch.ones(size, 1, device=device)\n",
    "    \n",
    "    return labels\n",
    "\n",
    "def get_fake_data_labels(size):\n",
    "    \"\"\"\n",
    "        获取虚假数据的标签\n",
    "        所有的假数据，标签都是 0\n",
    "    \"\"\"\n",
    "    labels = torch.zeros(size, 1, device=device)\n",
    "    \n",
    "    return labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "c8592d6c",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    噪声生成器\n",
    "\"\"\"\n",
    "def get_noise(size):\n",
    "    \"\"\"\n",
    "        给生成器准备数据\n",
    "        - 100维度的向量\n",
    "    \"\"\"\n",
    "    X = torch.randn(size, 100, device=device)\n",
    "    \n",
    "    return X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "0674b255",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取一批测试数据\n",
    "\n",
    "num_test_samples = 16\n",
    "test_noise = get_noise(num_test_samples)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "0264a778",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([16, 100])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_noise.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "d0c8c082",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1200x800 with 16 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "当前正在进行 第 42 轮 ....\n"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_4240\\2911288428.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     28\u001b[0m         \u001b[1;31m# 图像转向量 [b, 1, 28, 28] ---> [b, 784]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     29\u001b[0m         \u001b[1;31m# 从数据集中获取100个真实的手写数字图像\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 30\u001b[1;33m         \u001b[0mreal_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mbatch_real_data\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mview\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbatch_real_data\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msize\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdevice\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mdevice\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     31\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     32\u001b[0m         \u001b[1;31m# 噪声[b, 100]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "\"\"\"\n",
    "    训练过程\n",
    "\"\"\"\n",
    "g_losses = []\n",
    "d_losses = []\n",
    "\n",
    "for epoch in range(1, num_epochs+1):\n",
    "    \n",
    "    print(f\"当前正在进行 第 {epoch} 轮 ....\")\n",
    "    \n",
    "    # 设置训练模式\n",
    "    generator.train()\n",
    "    discriminator.train()\n",
    "    \n",
    "    # 遍历真实的图像\n",
    "    for batch_idx, (batch_real_data, _) in enumerate(data_loader):\n",
    "        \n",
    "               \n",
    "        \"\"\"\n",
    "        1, 先训练鉴别器\n",
    "            鉴别器就是一个二分类问题\n",
    "            - 给一批真数据，输出真\n",
    "            - 给一批假数据，输出假\n",
    "        \n",
    "        \"\"\"\n",
    "        \n",
    "        # 1.1 准备数据\n",
    "        # 图像转向量 [b, 1, 28, 28] ---> [b, 784]\n",
    "        # 从数据集中获取100个真实的手写数字图像\n",
    "        real_data = batch_real_data.view(batch_real_data.size(0), -1).to(device=device)\n",
    "        \n",
    "        # 噪声[b, 100]\n",
    "        # 随机生成100个100维度的噪声，用于生成假图像\n",
    "        noise = get_noise(real_data.size(0))\n",
    "        \n",
    "        # 根据噪声，生成假数据 \n",
    "        # [b, 100] --> [b, 784]\n",
    "        fake_data = generator(noise).detach()\n",
    "                \n",
    "        \n",
    "        # 1.2 训练过程\n",
    "        \n",
    "        # 鉴别器的优化器梯度情况\n",
    "        d_optimizer.zero_grad()\n",
    "        \n",
    "        # 对真实数据鉴别\n",
    "        real_pred = discriminator(real_data)\n",
    "        \n",
    "        # 计算真实数据的误差\n",
    "        real_loss = loss_fn(real_pred, get_real_data_labels(real_data.size(0)))\n",
    "        \n",
    "        # 真实数据的梯度回传\n",
    "        real_loss.backward()\n",
    "\n",
    "        \n",
    "        # 对假数据鉴别\n",
    "        fake_pred = discriminator(fake_data)\n",
    "        \n",
    "        # 计算假数据的误差\n",
    "        fake_loss = loss_fn(fake_pred, get_fake_data_labels(fake_data.size(0)))\n",
    "        \n",
    "        # 假数据梯度回传\n",
    "        fake_loss.backward()\n",
    "        \n",
    "        # 梯度更新\n",
    "        d_optimizer.step()\n",
    "        \n",
    "        d_losses.append((real_loss + fake_loss).item())\n",
    "        \n",
    "#         print(f\"鉴别器的损失:{real_loss + fake_loss}\")\n",
    "        \n",
    "        \n",
    "        \"\"\"2, 再训练生成器\"\"\"\n",
    "        \n",
    "        # 获取生成器的生成结果\n",
    "        fake_pred = generator(get_noise(real_data.size(0)))\n",
    "        \n",
    "        # 生产器梯度清空\n",
    "        g_optimizer.zero_grad()\n",
    "        \n",
    "        # 把假数据让鉴别器鉴别一下\n",
    "        d_pred = discriminator(fake_pred)\n",
    "        \n",
    "        # 计算损失\n",
    "        # 把一个假东西，给专家看，专家说是真的，这个时候，造假的水平就可以了\n",
    "        g_loss = loss_fn(d_pred, get_real_data_labels(d_pred.size(0)))\n",
    "        \n",
    "        # 梯度回传\n",
    "        g_loss.backward()\n",
    "        \n",
    "        # 参数更新\n",
    "        g_optimizer.step()\n",
    "        \n",
    "#         print(f\"生成器误差：{g_loss}\")\n",
    "        g_losses.append(g_loss.item())\n",
    "   \n",
    "    # 每轮训练之后，观察生成器的效果\n",
    "    generator.eval()\n",
    "    \n",
    "    with torch.no_grad():\n",
    "        \n",
    "        # 正向推理\n",
    "        img_pred = generator(test_noise)\n",
    "        img_pred = img_pred.view(img_pred.size(0), 28, 28).cpu().data\n",
    "        \n",
    "        # 画图\n",
    "        display.clear_output(wait=True)\n",
    "        \n",
    "        # 设置画图的大小\n",
    "        fig = plt.figure(1, figsize=(12, 8)) \n",
    "        # 划分为 4 x 4 的 网格\n",
    "        gs = gridspec.GridSpec(4, 4)\n",
    "        \n",
    "        # 遍历每一个\n",
    "        for i in range(4):\n",
    "            for j in range(4):\n",
    "                # 取每一个图\n",
    "                X = img_pred[i * 4 + j, :, :]\n",
    "                # 添加一个对应网格内的子图\n",
    "                ax = fig.add_subplot(gs[i, j])\n",
    "                # 在子图内绘制图像\n",
    "                ax.matshow(X, cmap=plt.get_cmap(\"Greys\"))\n",
    "#                 ax.set_xlabel(f\"{label}\")\n",
    "                ax.set_xticks(())\n",
    "                ax.set_yticks(())\n",
    "        plt.show()\n",
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "9fda406d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Generator(\n",
       "  (hidden0): Linear(in_features=100, out_features=256, bias=True)\n",
       "  (hidden1): Linear(in_features=256, out_features=512, bias=True)\n",
       "  (hidden2): Linear(in_features=512, out_features=784, bias=True)\n",
       ")"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "generator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "1d28e8d2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 1.9082, -0.8064,  1.0467,  1.3298, -1.1503,  0.2281,  0.2039,  1.9197,\n",
       "         -0.2345,  0.6919,  1.0736, -0.3273, -0.6705,  1.5962, -0.7937, -0.1740,\n",
       "         -0.9124, -0.6738,  0.9008, -0.6689,  0.2752, -1.5080,  0.8737,  0.7379,\n",
       "         -0.6768, -1.2768,  0.4384,  0.5583, -0.0306, -1.8420,  0.3285, -1.1224,\n",
       "          0.1329,  0.7275, -0.4579,  0.5543,  1.1923, -0.8505,  0.7687,  0.1843,\n",
       "         -0.9450,  0.1874, -2.4604,  0.2793, -2.5108, -0.1345, -0.3974,  0.0284,\n",
       "          0.2955,  0.2078, -0.8350, -0.4292, -0.2872, -0.7409,  1.2451, -1.1753,\n",
       "         -0.5343,  1.7507, -0.4835,  0.1329,  0.7961, -1.7286, -0.9160,  0.1881,\n",
       "          0.0841, -0.6147,  0.2920, -1.3368,  0.6853, -3.8114,  1.7305,  0.2395,\n",
       "         -1.0582, -0.4707, -0.9109,  0.5286,  1.7341,  0.1892,  1.1994,  0.1909,\n",
       "         -0.0122, -1.7830, -1.9489, -1.2490, -1.1123, -0.0329, -1.0267, -0.5688,\n",
       "          0.3707, -0.5750,  0.4154, -0.3051, -1.3248, -0.4750,  1.5237, -0.2450,\n",
       "          0.0258, -0.5909,  0.0297, -0.2134]], device='cuda:0')"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "get_noise(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "b4c4c7da",
   "metadata": {},
   "outputs": [],
   "source": [
    "img = generator(get_noise(1)).detach()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "7ce1f605",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9998, -0.9999,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -0.9994, -1.0000, -0.9998, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -0.9996, -1.0000, -0.9999, -1.0000, -1.0000, -0.9996, -1.0000, -1.0000,\n",
       "         -0.9999, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9995, -0.9998,\n",
       "         -0.9999, -1.0000, -1.0000, -0.9999, -0.9999, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9998, -1.0000,\n",
       "         -1.0000, -0.9998, -1.0000, -1.0000, -1.0000, -0.9998, -0.9997, -1.0000,\n",
       "         -1.0000, -0.9999, -1.0000, -1.0000, -0.9973, -0.9992, -1.0000, -1.0000,\n",
       "         -0.9998, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9994, -0.9994,\n",
       "         -1.0000, -1.0000, -1.0000, -0.9999, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -0.9998, -1.0000, -1.0000, -0.9999, -0.9999, -0.9998, -1.0000,\n",
       "         -0.9998, -0.9999, -1.0000, -1.0000, -0.9999, -1.0000, -0.9997, -1.0000,\n",
       "         -1.0000, -0.9992, -1.0000, -1.0000, -1.0000, -0.9999, -1.0000, -1.0000,\n",
       "         -0.9999, -0.9999, -1.0000, -0.9999, -0.9996, -1.0000, -0.9999, -0.9952,\n",
       "         -0.9510,  0.4929,  0.3118, -0.8870, -0.9845, -0.9997, -0.9999, -1.0000,\n",
       "         -0.9998, -1.0000, -1.0000, -1.0000, -1.0000, -0.9999, -1.0000, -0.9992,\n",
       "         -1.0000, -0.9998, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -0.9999, -0.9995, -0.9938, -0.8227,  0.9446,  0.8861,  0.9415,\n",
       "         -0.3853, -0.9889, -1.0000, -1.0000, -0.9991, -0.9909, -0.9999, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -0.9999, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -0.9999, -1.0000, -1.0000, -0.9957, -0.9489,\n",
       "          0.8120,  0.9788,  0.9969,  0.8504, -0.6553, -0.9980, -0.9998, -0.9997,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9999, -1.0000,\n",
       "         -0.9999, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9998, -1.0000,\n",
       "         -1.0000, -0.9995, -0.8819, -0.7058,  0.4122,  0.9366,  0.6774, -0.7435,\n",
       "         -0.9896, -0.9980, -0.9995, -1.0000, -1.0000, -0.9997, -1.0000, -1.0000,\n",
       "         -1.0000, -0.9997, -1.0000, -1.0000, -1.0000, -0.9993, -0.9998, -0.9990,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9999, -0.9321,  0.0570,\n",
       "          0.9687,  0.9786,  0.2730, -0.9619, -0.9984, -0.9999, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -0.9994, -1.0000, -1.0000, -0.9999, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -0.9999, -0.9989, -0.9998, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -0.9747,  0.8047,  0.9893,  0.9971,  0.3046, -0.9969,\n",
       "         -0.9994, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9999, -0.9998, -0.9971,\n",
       "         -0.9995, -0.9997, -1.0000, -1.0000, -1.0000, -0.9996, -0.3666,  0.9990,\n",
       "          0.9999,  0.9968,  0.1918, -0.9954, -0.9999, -1.0000, -0.9999, -0.9998,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -0.9998, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -0.9999, -0.9999, -0.9980, -0.9986, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -0.6377,  0.9018,  1.0000,  1.0000,  0.9968, -0.8691, -0.9989,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -0.9992, -1.0000, -0.9989, -0.9998,\n",
       "         -1.0000, -0.9999, -1.0000, -0.9996, -1.0000, -0.9999, -0.9998, -0.9979,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -0.9980,  0.8445,  0.9999,  1.0000,\n",
       "          0.9999, -0.1490, -0.9974, -0.9998, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -0.9999, -1.0000, -1.0000, -1.0000, -1.0000, -0.9963,\n",
       "         -1.0000, -1.0000, -0.9999, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -0.8805,  0.9951,  1.0000,  1.0000,  0.8859, -0.9383, -0.9959, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -0.9984, -0.9999, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -0.7400,  0.9288,  0.9997,  1.0000,  0.9973,\n",
       "          0.1643, -0.9970, -0.9973, -0.9998, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -0.9998, -1.0000, -1.0000, -1.0000, -1.0000, -0.9999, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9999, -0.8623,\n",
       "          0.8006,  0.9996,  0.9999,  0.8024, -0.9978, -0.9994, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -0.9999, -0.9986, -1.0000, -0.9970,\n",
       "         -1.0000, -1.0000, -0.9997, -0.9999, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -0.9999, -0.9819,  0.9766,  0.9999,  0.9855, -0.7948,\n",
       "         -0.9995, -0.9999, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -0.9999, -1.0000, -1.0000, -0.9998, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9863,  0.6901,\n",
       "          0.9969,  0.9999,  0.9571, -0.7945, -0.9925, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9999, -0.9823,\n",
       "         -1.0000, -0.9994, -1.0000, -0.9996, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -0.5821,  0.9990,  1.0000,  0.9962, -0.4137, -0.4612,\n",
       "         -0.9601, -0.9997, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -0.9998, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9541,  0.9602,  0.9999,\n",
       "          1.0000,  0.9706, -0.9283, -0.9978, -0.9920, -0.9999, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -0.9998, -0.9998, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -0.9980, -1.0000, -0.9997, -1.0000, -1.0000,\n",
       "         -1.0000, -0.7885,  0.9942,  0.9999,  0.9976, -0.9657, -0.9974, -0.9980,\n",
       "         -0.9996, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -0.9987, -1.0000, -1.0000, -1.0000, -1.0000, -0.9999,\n",
       "         -1.0000, -1.0000, -0.9998, -1.0000, -0.8674,  0.4086,  0.9970,  0.9988,\n",
       "          0.9442, -0.9970, -0.9926, -0.9998, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -0.9997, -1.0000, -0.9998, -1.0000,\n",
       "         -1.0000, -0.9999, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9989,\n",
       "         -0.1202,  0.9940,  0.9955,  0.9835, -0.4748, -1.0000, -1.0000, -0.9999,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9992,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -0.9999, -0.9996, -0.9997, -0.9996,\n",
       "         -0.9994, -0.9989, -0.9999, -0.9846, -0.5038,  0.7643,  0.9975,  0.9796,\n",
       "         -0.9605, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -0.9999, -1.0000, -0.9999, -0.9997, -1.0000, -0.9999, -0.9993,\n",
       "         -0.9998, -1.0000, -1.0000, -1.0000, -0.9993, -1.0000, -0.9999, -0.9986,\n",
       "         -0.9334, -0.3136, -0.5891, -0.9040, -0.9963, -1.0000, -1.0000, -1.0000,\n",
       "         -0.9995, -0.9999, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9998,\n",
       "         -1.0000, -1.0000, -1.0000, -0.9997, -1.0000, -0.9999, -0.9982, -0.9998,\n",
       "         -0.9997, -1.0000, -0.9999, -1.0000, -1.0000, -0.9994, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -0.9998, -1.0000, -0.9999, -0.9999, -0.9997,\n",
       "         -1.0000, -1.0000, -0.9996, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9998, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9999, -0.9986, -0.9999,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9999, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9999, -1.0000,\n",
       "         -0.9924, -1.0000, -0.9999, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
       "         -1.0000, -1.0000, -1.0000, -1.0000, -0.9998, -1.0000, -0.9999, -1.0000]],\n",
       "       device='cuda:0')"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "img"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "62df4848",
   "metadata": {},
   "outputs": [],
   "source": [
    "img1 = ((img * 0.5 + 0.5) * 255).cpu().numpy().astype(int).reshape(28, 28)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "f4d5ad19",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x2217c1e9c40>"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGdCAYAAAC7EMwUAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAZwUlEQVR4nO3df0xV9/3H8ddV8Uot3I4o3HsrMtLoflRnUutU0vqji0TWGalbYttkwSwxdv5YCG3cnFlk+0M6k5r9weqyZvFbuzr9Y+pcZtqyKahxLmro6lhnaMWCEUYlei+ivRT9fP8w3uwWRc71Xt5ceD6ST9J7znlz3pweefHhnnOuzznnBACAgTHWDQAARi9CCABghhACAJghhAAAZgghAIAZQggAYIYQAgCYIYQAAGbGWTfwRbdu3dKlS5eUk5Mjn89n3Q4AwCPnnLq7uxUOhzVmzMBznWEXQpcuXVJhYaF1GwCAB9TW1qYpU6YMuM2w+3NcTk6OdQsAgBQYzM/ztIXQ66+/ruLiYk2YMEGzZ8/WsWPHBlXHn+AAYGQYzM/ztITQ3r17VVlZqc2bN6uxsVFPP/20ysrK1Nramo7dAQAylC8dT9GeO3eunnjiCe3YsSO+7Gtf+5rKy8tVU1MzYG00GlUgEEh1SwCAIRaJRJSbmzvgNimfCfX29urMmTMqLS1NWF5aWqoTJ0702z4WiykajSYMAMDokPIQunz5sm7evKmCgoKE5QUFBero6Oi3fU1NjQKBQHxwZRwAjB5puzDhi29IOefu+ibVpk2bFIlE4qOtrS1dLQEAhpmU3yc0adIkjR07tt+sp7Ozs9/sSJL8fr/8fn+q2wAAZICUz4TGjx+v2bNnq66uLmF5XV2dSkpKUr07AEAGS8sTE6qqqvT9739fTz75pObPn6/f/va3am1t1UsvvZSO3QEAMlRaQmjlypXq6urSL37xC7W3t2vGjBk6dOiQioqK0rE7AECGSst9Qg+C+4QAYGQwuU8IAIDBIoQAAGYIIQCAGUIIAGCGEAIAmCGEAABmCCEAgBlCCABghhACAJghhAAAZgghAIAZQggAYIYQAgCYIYQAAGYIIQCAGUIIAGCGEAIAmCGEAABmCCEAgBlCCABghhACAJghhAAAZgghAIAZQggAYIYQAgCYIYQAAGYIIQCAGUIIAGCGEAIAmCGEAABmCCEAgBlCCABghhACAJghhAAAZgghAIAZQggAYIYQAgCYIYQAAGYIIQCAmXHWDQBIn/HjxydV984773iu+e9//+u5Zs2aNZ5ruru7Pdc45zzXYGgwEwIAmCGEAABmCCEAgBlCCABghhACAJghhAAAZgghAIAZQggAYIYQAgCYIYQAAGYIIQCAGUIIAGCGB5gCI9gjjzySVN38+fM918RiMc81yTz0dOXKlZ5r/vznP3uukYb3g099Pl9SdcPte2ImBAAwQwgBAMykPISqq6vl8/kSRjAYTPVuAAAjQFreE3r88cf117/+Nf567Nix6dgNACDDpSWExo0bx+wHAHBfaXlPqLm5WeFwWMXFxXr++ed1/vz5e24bi8UUjUYTBgBgdEh5CM2dO1e7du3Su+++qzfeeEMdHR0qKSlRV1fXXbevqalRIBCIj8LCwlS3BAAYpnwuzReN9/T06LHHHtPGjRtVVVXVb30sFku4vyAajRJEQIrk5+cnVffJJ594rknmPiG/3++5hvuEbsuE+4QikYhyc3MH3CbtN6tOnDhRM2fOVHNz813X+/3+pE5EAEDmS/t9QrFYTB9++KFCoVC6dwUAyDApD6FXXnlFDQ0Namlp0T/+8Q9973vfUzQaVUVFRap3BQDIcCn/c9zFixf1wgsv6PLly5o8ebLmzZunkydPqqioKNW7AgBkuJSH0J49e1L9JQFIGj9+vOeaf/7zn0ntKysry3NNMu/t3uuq2YF8/PHHnmuG8wUGyRop3xPPjgMAmCGEAABmCCEAgBlCCABghhACAJghhAAAZgghAIAZQggAYIYQAgCYIYQAAGYIIQCAGUIIAGAm7R9qB6C/QCDguWby5Mmea06fPu25RpK+9a1vea5paWnxXPPss896rknmU18xfDETAgCYIYQAAGYIIQCAGUIIAGCGEAIAmCGEAABmCCEAgBlCCABghhACAJghhAAAZgghAIAZQggAYIYQAgCY4SnagIFYLOa55gc/+IHnmqVLl3qukSSfz+e55syZM55rLl686LnGOee5BsMXMyEAgBlCCABghhACAJghhAAAZgghAIAZQggAYIYQAgCYIYQAAGYIIQCAGUIIAGCGEAIAmCGEAABmeIApYODzzz/3XLNq1SrPNWPGJPd7ZjIPMB03zvuPk76+Ps81GFmYCQEAzBBCAAAzhBAAwAwhBAAwQwgBAMwQ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\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(X=img1, cmap=\"gray\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "id": "30ee1517",
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_fake_img():\n",
    "    with torch.no_grad():\n",
    "        noise = torch.randn(1, 100).cuda()\n",
    "        img = generator(noise)\n",
    "        img = ((img * 0.5 + 0.5) * 255).cpu().numpy().astype(int).reshape(28, 28)\n",
    "        plt.imshow(X=img, cmap=\"gray\")\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "id": "fb3cc1c9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaEAAAGdCAYAAAC7EMwUAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAbBElEQVR4nO3df2zUdx3H8dfB6FFIe1pZe3eja7rJgtIFM0CgMn4lNHQRZWjCWGLKH+I2AUM6MmXEgP5BJwQyEzbUxSBkMIiGMQzEWQMt2zoMEHAdLoSNIlVoKmTrlQLXFT7+0XDxKL++39313bt7PpJvwn3v++733W+/9NXP3fc+34BzzgkAAAODrBsAAOQuQggAYIYQAgCYIYQAAGYIIQCAGUIIAGCGEAIAmCGEAABm7rNu4GbXr1/XuXPnVFBQoEAgYN0OAMAj55w6OzsVjUY1aNCdxzoDLoTOnTun0tJS6zYAAF9Qa2urRo4cecdtBtzLcQUFBdYtAABS4F5+n6cthF599VWVl5dr6NChGjdunN555517quMlOAC5JhAIeF4ywb30mZYQ2rlzp5YtW6aVK1fq2LFjevzxx1VdXa2zZ8+mY3cAgAwVSMcs2hMnTtRjjz2mTZs2JdZ97Wtf09y5c1VXV3fH2lgsplAolOqWAGDA8jOyyYQbIHR0dKiwsPCO26R8JNTd3a2jR4+qqqoqaX1VVZWampr6bB+PxxWLxZIWAEBuSHkIXbhwQdeuXVNJSUnS+pKSErW1tfXZvq6uTqFQKLFwZRwA5I60XZhw8/DSOXfLIeeKFSvU0dGRWFpbW9PVEgBggEn554RGjBihwYMH9xn1tLe39xkdSVIwGFQwGEx1GwCADJDykVBeXp7GjRun+vr6pPX19fWqrKxM9e4AABksLTMm1NbW6gc/+IHGjx+vyZMn63e/+53Onj2rZ599Nh27AwBkqLSE0Pz583Xx4kX98pe/1Pnz51VRUaF9+/aprKwsHbsDAGSotHxO6Ivgc0LZLVs/D5Ft+DkhFUw+JwQAwL0ihAAAZgghAIAZQggAYIYQAgCYIYQAAGYIIQCAGUIIAGCGEAIAmCGEAABmCCEAgBlCCABgJi2zaAO3wySXmYGfE/oLIyEAgBlCCABghhACAJghhAAAZgghAIAZQggAYIYQAgCYIYQAAGYIIQCAGUIIAGCGEAIAmCGEAABmCCEAgBlCCABghhACAJghhAAAZgghAIAZQggAYIYQAgCYIYQAAGYIIQCAGUIIAGCGEAIAmCGEAABmCCEAgBlCCABg5j7rBgBkh0GDvP9N66emp6fHcw0GLkZCAAAzhBAAwAwhBAAwQwgBAMwQQgAAM4QQAMAMIQQAMEMIAQDMEEIAADOEEADADCEEADBDCAEAzDCBKYCUeOihhzzXLFiwwHPNunXrPNcMHjzYc40kdXV1+arLNkOGDPG0vXPunieaZSQEADBDCAEAzKQ8hFavXq1AIJC0hMPhVO8GAJAF0vKe0JgxY/S3v/0t8djv67EAgOyWlhC67777GP0AAO4qLe8JnTp1StFoVOXl5Xrqqad0+vTp224bj8cVi8WSFgBAbkh5CE2cOFFbt27V22+/rddee01tbW2qrKzUxYsXb7l9XV2dQqFQYiktLU11SwCAASrgnHPp3EFXV5cefvhhvfDCC6qtre3zfDweVzweTzyOxWIEEZCBvvrVr3qu4XNCmcHv54Q6OjpUWFh4x23T/mHV4cOH69FHH9WpU6du+XwwGFQwGEx3GwCAASjtnxOKx+P66KOPFIlE0r0rAECGSXkILV++XI2NjWppadHf//53ff/731csFlNNTU2qdwUAyHApfznu3//+txYsWKALFy7o/vvv16RJk3To0CGVlZWlelcAgAyX8hDasWNHqr8k4JnfN6KLi4s915w/f97XvrwaMWKE55pAIOBrX37+aPzzn//sueZeJ7n8fx9++KHnmmPHjnmukbgw4YbPP/88bV+bueMAAGYIIQCAGUIIAGCGEAIAmCGEAABmCCEAgBlCCABghhACAJghhAAAZgghAIAZQggAYIYQAgCYSfudVb2KxWIKhULWbWAAycvL81yzdetWX/v6xz/+4bnm17/+teeay5cve67xMxnp3e5qeTuvv/6655onnnjCc83Vq1c91/i5CeZ996X9/p24hXu5syojIQCAGUIIAGCGEAIAmCGEAABmCCEAgBlCCABghhACAJghhAAAZgghAIAZQggAYIYQAgCYIYQAAGYIIQCAGaaWRb/asWOH55rvfOc7nmvy8/M910jSW2+95bnGz4zYfviZPfrnP/+5r31VVlZ6rhk0yPvftMOGDfNc097e7rkGAxcjIQCAGUIIAGCGEAIAmCGEAABmCCEAgBlCCABghhACAJgh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\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "generate_fake_img()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ec0768a6",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
